package com.accloud.cloudservice;

import com.accloud.service.ACObject;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.MappingJsonFactory;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.List;

public class ACObjectMarshaller {
    public static byte[] marshal(ACObject zo) throws IOException {
        JsonFactory jsonFactory = new MappingJsonFactory();
        StringWriter output = new StringWriter();
        JsonGenerator jsonGenerator = jsonFactory.createGenerator(output);
        marshalObject(zo, jsonGenerator);
        jsonGenerator.flush();
        return output.toString().getBytes();
    }

    private static void marshalObject(ACObject zo, JsonGenerator jsonGenerator) throws IOException {
        jsonGenerator.writeStartObject();
        for (String key : zo.getKeys()) {
            Object o = zo.get(key);
            if (o instanceof ACObject) {
                jsonGenerator.writeFieldName(key);
                marshalObject((ACObject) o, jsonGenerator);
            } else if (o instanceof List) {
                jsonGenerator.writeArrayFieldStart(key);
                for (Object a : (List) o) {
                    if (a instanceof ACObject) {
                        marshalObject((ACObject) a, jsonGenerator);
                    } else {
                        jsonGenerator.writeObject(a);
                    }
                }
                jsonGenerator.writeEndArray();
            } else {
                jsonGenerator.writeObjectField(key, o);
            }
        }
        jsonGenerator.writeEndObject();
    }

    public static void unmarshal(ACObject zo, byte[] payload) throws IOException {
        if (payload != null) {
            JsonParser jsonParser = new MappingJsonFactory().createParser(new StringReader(new String(payload)));
            JsonToken t = jsonParser.nextToken();
            if (JsonToken.START_OBJECT == t) {
                unmarshallObject(zo, jsonParser);
            } else if (JsonToken.START_ARRAY == t) {
                while (true) {
                    JsonToken t2 = jsonParser.nextToken();
                    if (JsonToken.END_ARRAY == t2) {
                        return;
                    }
                    if (JsonToken.START_OBJECT == t2) {
                        ACObject a = new ACObject();
                        unmarshallObject(a, jsonParser);
                        zo.add("defaultKey", a);
                    } else {
                        zo.add("defaultKey", unmarshalValue(t2, jsonParser));
                    }
                }
            } else {
                throw new IOException("wrong json format");
            }
        }
    }

    private static void unmarshallObject(ACObject zo, JsonParser jsonParser) throws IOException {
        while (JsonToken.END_OBJECT != jsonParser.nextToken()) {
            unmarshalField(zo, jsonParser);
        }
    }

    private static void unmarshalField(ACObject zo, JsonParser jsonParser) throws IOException {
        String key = jsonParser.getCurrentName();
        JsonToken t = jsonParser.nextToken();
        if (JsonToken.START_OBJECT == t) {
            ACObject o = new ACObject();
            unmarshallObject(o, jsonParser);
            zo.put(key, o);
        } else if (JsonToken.START_ARRAY == t) {
            while (true) {
                JsonToken t2 = jsonParser.nextToken();
                if (JsonToken.END_ARRAY == t2) {
                    return;
                }
                if (JsonToken.START_OBJECT == t2) {
                    ACObject a = new ACObject();
                    unmarshallObject(a, jsonParser);
                    zo.add(key, a);
                } else {
                    zo.add(key, unmarshalValue(t2, jsonParser));
                }
            }
        } else {
            zo.put(key, unmarshalValue(t, jsonParser));
        }
    }

    private static Object unmarshalValue(JsonToken t, JsonParser jsonParser) throws IOException {
        if (JsonToken.VALUE_STRING == t) {
            return jsonParser.getValueAsString();
        }
        if (JsonToken.VALUE_TRUE == t || JsonToken.VALUE_FALSE == t) {
            return Boolean.valueOf(jsonParser.getValueAsBoolean());
        }
        if (JsonToken.VALUE_NUMBER_INT == t) {
            return Long.valueOf(jsonParser.getValueAsLong());
        }
        if (JsonToken.VALUE_NUMBER_FLOAT == t) {
            return Double.valueOf(jsonParser.getValueAsDouble());
        }
        return null;
    }
}
